#include <SPI.h>

// 引脚定义
#define MISO_GPIO 12
#define MOSI_GPIO 11
#define SCK_GPIO 13
#define CS_GPIO 14
#define INT_GPIO 10
#define LED_PIN 4

// SPI设置
#define SPI_FREQ 20000000  // 提升到20MHz (规格书P61支持最高80MHz)
#define BUFFER_SIZE 2048

unsigned long lastLinkCheck = 0;

// W5500寄存器地址 (规格书P29-44)
#define W5500_MR        0x0000
#define W5500_GAR       0x0001
#define W5500_SUBR      0x0005
#define W5500_SHAR      0x0009
#define W5500_SIPR      0x000F
#define W5500_RCR       0x001B
#define W5500_VERSION   0x0039
#define W5500_S0_MR     0x0400  // Socket0模式寄存器
#define W5500_S0_CR     0x0401  // Socket0命令寄存器
#define W5500_S0_IR     0x0402  // Socket0中断寄存器
#define W5500_S0_SR     0x0403  // Socket0状态寄存器
#define W5500_S0_RX_RSR0 0x0426 // 接收数据大小寄存器0
#define W5500_S0_RX_RSR1 0x0427 // 接收数据大小寄存器1
#define W5500_S0_RX_RD0  0x0428 // 接收读指针0
#define W5500_S0_RX_RD1  0x0429 // 接收读指针1
#define W5500_S0_RX_BUF  0x6000 // 接收缓冲区基地址 (规格书P28)

// 块选择常量定义 (规格书P15)
#define BSB_COMMON 0x00  // 00000 - 公共寄存器块
#define BSB_S0_REG 0x01  // 00001 - Socket0寄存器块
#define BSB_S0_RX  0x03  // 00011 - Socket0 RX缓冲区块

// 全局变量
uint8_t mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
uint8_t ip[] = {192, 168, 32, 232};
uint8_t gw[] = {192, 168, 32, 1};
uint8_t sn[] = {255, 255, 255, 0};
uint8_t packetBuffer[BUFFER_SIZE];

// 在全局变量区添加SSH端口定义
#define SSH_PORT 22

// 带块选择的寄存器写函数
void writeW5500Reg(uint16_t reg, uint8_t bsb, uint8_t val) {
  digitalWrite(CS_GPIO, LOW);
  SPI.beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE0));
  SPI.transfer(reg >> 8);
  SPI.transfer(reg & 0xFF);
  SPI.transfer((bsb << 3) | 0x04); // 控制字节: BSB + 写 + VDM
  SPI.transfer(val);
  SPI.endTransaction();
  digitalWrite(CS_GPIO, HIGH);
  delayMicroseconds(1);
}

// 带块选择的寄存器读函数
uint8_t readW5500Reg(uint16_t reg, uint8_t bsb) {
  digitalWrite(CS_GPIO, LOW);
  SPI.beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE0));
  SPI.transfer(reg >> 8);
  SPI.transfer(reg & 0xFF);
  SPI.transfer((bsb << 3) | 0x00); // 控制字节: BSB + 读 + VDM
  uint8_t val = SPI.transfer(0);
  SPI.endTransaction();
  digitalWrite(CS_GPIO, HIGH);
  delayMicroseconds(1);
  return val;
}

// 带块选择的数据块读函数
void readW5500Block(uint16_t addr, uint8_t bsb, uint8_t* buf, uint16_t len) {
  digitalWrite(CS_GPIO, LOW);
  delayMicroseconds(10); // 增加CS低电平延时
  SPI.beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE0));
  SPI.transfer(addr >> 8);
  SPI.transfer(addr & 0xFF);
  SPI.transfer((bsb << 3) | 0x00); // 控制字节: BSB + 读 + VDM
  for (uint16_t i = 0; i < len; i++) {
    buf[i] = SPI.transfer(0);
  }
  SPI.endTransaction();
  digitalWrite(CS_GPIO, HIGH);
  delayMicroseconds(1);
}

// 配置网络
void configNetwork() {
  for (int i = 0; i < 6; i++) writeW5500Reg(W5500_SHAR + i, BSB_COMMON, mac[i]);
  for (int i = 0; i < 4; i++) writeW5500Reg(W5500_SIPR + i, BSB_COMMON, ip[i]);
  for (int i = 0; i < 4; i++) writeW5500Reg(W5500_GAR + i, BSB_COMMON, gw[i]);
  for (int i = 0; i < 4; i++) writeW5500Reg(W5500_SUBR + i, BSB_COMMON, sn[i]);
}

// 初始化W5500并设置MACRAW模式
bool initW5500() {
  pinMode(INT_GPIO, INPUT_PULLUP);
  
  // 初始化SPI
  SPI.begin(SCK_GPIO, MISO_GPIO, MOSI_GPIO, CS_GPIO);
  delay(100);
  
  // 软复位 (使用公共寄存器块)
  writeW5500Reg(W5500_MR, BSB_COMMON, 0x80);
  delay(100);
  while (readW5500Reg(W5500_MR, BSB_COMMON) & 0x80);
  delay(100);
  
  // 检查版本
  if (readW5500Reg(W5500_VERSION, BSB_COMMON) != 0x04) {
    Serial.println("错误：W5500版本不是0x04");
    return false;
  }
  
  // 配置网络参数
  configNetwork();
  
  // === 关键修改：正确配置MACRAW模式 ===
  // 步骤1: 关闭Socket0 (确保在配置前关闭)
  writeW5500Reg(W5500_S0_CR, BSB_S0_REG, 0x10); // CLOSE命令
  delay(10);

  // 步骤2: 配置Socket0为MACRAW模式 (规格书P45)
  writeW5500Reg(W5500_S0_MR, BSB_S0_REG, 0x04); // MACRAW模式(0x04)
  
  // 步骤3: 设置接收缓冲区大小 (8KB = 0x08) (规格书P52)
  writeW5500Reg(0x001E, BSB_S0_REG, 0x08); // Sn_RXBUF_SIZE=8(8KB)
  
  // 步骤4: 打开Socket0
  writeW5500Reg(W5500_S0_CR, BSB_S0_REG, 0x01); // OPEN命令
  delay(50); // 增加延时确保命令执行

  // 步骤5: 检查状态并重试
  uint8_t status = readW5500Reg(W5500_S0_SR, BSB_S0_REG);
  int retryCount = 0;
  
  while (status != 0x42 && retryCount < 5) {
    Serial.print("Socket0状态: 0x");
    Serial.print(status, HEX);
    Serial.println(" - 尝试重新打开...");
    
    // 关闭并重新打开
    writeW5500Reg(W5500_S0_CR, BSB_S0_REG, 0x10); // CLOSE
    delay(10);
    writeW5500Reg(W5500_S0_MR, BSB_S0_REG, 0x04); // 重新设置模式
    writeW5500Reg(W5500_S0_CR, BSB_S0_REG, 0x01); // OPEN
    delay(50);
    
    status = readW5500Reg(W5500_S0_SR, BSB_S0_REG);
    retryCount++;
  }

  if (status != 0x42) {
    Serial.print("错误：无法打开Socket0，最终状态: 0x");
    Serial.println(status, HEX);
    return false;
  }

  // 设置接收所有数据包 (规格书P38)
  writeW5500Reg(W5500_RCR, BSB_COMMON, 0x03); // 接收所有包
  
  Serial.println("W5500初始化完成，进入MACRAW模式");
  return true;
}

// 处理数据包
void processPackets() {
  if (!isLinkUp()) {
    clearRxBuffer(); // 网线断开时清空缓冲区
    return;
  }
  // 添加状态检查
  uint8_t status = readW5500Reg(W5500_S0_SR, BSB_S0_REG);
  if (status != 0x42) {
    Serial.print("警告：Socket0状态异常: 0x");
    Serial.println(status, HEX);
    return;
  }
  
  // 读取接收数据大小 (规格书P55)
  uint16_t rxSize = (readW5500Reg(W5500_S0_RX_RSR0, BSB_S0_REG) << 8) | 
                   readW5500Reg(W5500_S0_RX_RSR1, BSB_S0_REG);
  if (rxSize < 2) return; // 至少需要2字节头部
  
  // 读取读指针
  uint16_t rxRd = (readW5500Reg(W5500_S0_RX_RD0, BSB_S0_REG) << 8) | 
                 readW5500Reg(W5500_S0_RX_RD1, BSB_S0_REG);
  
  // 读取2字节头部 (使用RX缓冲区块)
  uint8_t header[2];
  readW5500Block(rxRd, BSB_S0_RX, header, 2);
  
  // 解析数据包长度 (大端格式)
  uint16_t packetLen = (header[0] << 8) | header[1];
  
  // 验证长度有效性
  if (packetLen < 14 || packetLen > 1518 || packetLen > BUFFER_SIZE) {
    // 无效数据包，跳过
    uint16_t newRxRd = (rxRd + 2) & 0x1FFF;
    writeW5500Reg(W5500_S0_RX_RD0, BSB_S0_REG, newRxRd >> 8);
    writeW5500Reg(W5500_S0_RX_RD1, BSB_S0_REG, newRxRd & 0xFF);
    writeW5500Reg(W5500_S0_CR, BSB_S0_REG, 0x40); // RECV命令
    return;
  }
  
  // 读取以太网帧数据 (使用RX缓冲区块)
  readW5500Block(rxRd + 2, BSB_S0_RX, packetBuffer, packetLen);
  
  // 更新读指针
  uint16_t newRxRd = (rxRd + 2 + packetLen) & 0x1FFF;
  writeW5500Reg(W5500_S0_RX_RD0, BSB_S0_REG, newRxRd >> 8);
  writeW5500Reg(W5500_S0_RX_RD1, BSB_S0_REG, newRxRd & 0xFF);
  writeW5500Reg(W5500_S0_CR, BSB_S0_REG, 0x40); // RECV命令
  
  // 解析数据包
  parsePacket(packetBuffer, packetLen);
}

// 解析数据包 (保持不变)
void parsePacket(uint8_t* ethFrame, uint16_t ethFrameLen) {
  // Serial.print("Link: ");
  // Serial.print(isLinkUp() ? "UP" : "DOWN");
  // Serial.print(" | Packet Len: ");
  // Serial.println(ethFrameLen);
  // 跳过2字节长度头
  uint8_t* buffer = ethFrame;
  uint16_t length = ethFrameLen; // 实际以太网帧长度
  // 这里添加你的数据包解析逻辑
  // 示例：打印数据包长度
  //Serial.print("收到数据包，长度: ");
  // Serial.println(length);
  // 调试输出前16字节内容
  //Serial.println("数据包头部16字节:");
  // for(int i=0; i<16; i++){
  //   if(buffer[i]<0x10) Serial.print("0");
  //   Serial.print(buffer[i], HEX);
  //   Serial.print(" ");
  //   if(i==13) Serial.println(); // 以太网头结束处换行
  // }
  // Serial.println();
  // 基本长度检查（以太网帧头14字节 + IP头至少20字节 + TCP头至少20字节）
  //Serial.println("丢弃：数据包长度不足54字节");
  if (length < 54) return; // 不是完整TCP/IP包

  // 解析以太网帧头（前14字节）
  uint8_t* ethHeader = buffer;
  uint8_t* srcMac = ethHeader + 6;  // 源MAC地址偏移6字节
  uint8_t* dstMac = ethHeader;      // 目标MAC地址开头
// 调试输出MAC地址
  // Serial.print("目标MAC: ");
  // printMac(dstMac);
  // Serial.print("源MAC: ");
  // printMac(srcMac);

  // 检查以太网类型
  // Serial.print("以太网类型: 0x");
  // Serial.print(ethHeader[12], HEX);
  // Serial.println(ethHeader[13], HEX);
  // 检查是否为IP协议（以太网类型0x0800）
  if(!(ethHeader[12] == 0x08 && ethHeader[13] == 0x00)){
    //Serial.println("丢弃：非IP协议数据包");
    return;
  }
  // 2. IP帧检查
  if(length < 34){ // 14(以太网) + 20(最小IP头)
    //Serial.println("丢弃：长度不足以容纳IP头");
    return;
  }
  
  // 解析IP头
  uint8_t* ipHeader = buffer + 14;
  uint8_t ipVer = (ipHeader[0] >> 4);
  uint8_t ipHeaderLength = (ipHeader[0] & 0x0F) * 4;
  
  // Serial.print("IP版本: ");
  // Serial.println(ipVer);
  // Serial.print("IP头长度: ");
  // Serial.println(ipHeaderLength);

  if(ipVer != 4){
    //Serial.println("丢弃：非IPv4数据包");
    return;
  }

  // 检查协议类型
  uint8_t protocol = ipHeader[9];
  // Serial.print("IP协议号: ");
  // Serial.println(protocol);
   
  if(protocol != 6){
    // Serial.print("TCP数据包检测结果: 0x");
    // Serial.print(protocol, HEX);
    // Serial.println(",注意：当前捕获到的是非TCP流量");
    return;
  }
  
  // 解析TCP头
  uint8_t* tcpHeader = ipHeader + ipHeaderLength;
  uint16_t srcPort = (tcpHeader[0] << 8) | tcpHeader[1];
  uint16_t dstPort = (tcpHeader[2] << 8) | tcpHeader[3];
  
  Serial.print("\t源端口: \t");
  Serial.print(srcPort);
  Serial.print("\t目标端口: \t");
  Serial.println(dstPort);

  // 检查SSH端口
  if(srcPort == SSH_PORT || dstPort == SSH_PORT){
    Serial.println(">>> 检测到SSH流量 <<<");
    Serial.print("源MAC: ");
    printMac(srcMac);
    Serial.print("目标MAC: ");
    printMac(dstMac);
    
    // 打印IP地址
    Serial.print("源IP: ");
    for(int i=0; i<4; i++){
      Serial.print(ipHeader[12+i]);
      if(i<3) Serial.print(".");
    }
    Serial.println();
    
    Serial.print("目标IP: ");
    for(int i=0; i<4; i++){
      Serial.print(ipHeader[16+i]);
      if(i<3) Serial.print(".");
    }
    Serial.println();
  }
  else {
    Serial.println("非SSH端口流量");
  }
}
// void parsePacket(uint8_t* buffer, uint16_t length) {
//   // 跳过2字节长度头
//   uint8_t* ethFrame = buffer + 2;
//   uint16_t ethFrameLen = length - 2; // 实际以太网帧长度

//   // 以太网头解析（从ethFrame[0]开始）
//   if (ethFrameLen < 14) return;
//   uint8_t* srcMac = ethFrame + 6;
//   uint8_t* dstMac = ethFrame;
//   uint16_t ethType = (ethFrame[12] << 8) | ethFrame[13];

//   // 仅处理IPv4包(0x0800)
//   if (ethType != 0x0800 || ethFrameLen < 34) return;

//   // IP头解析（ethFrame+14开始）
//   uint8_t* ipHeader = ethFrame + 14;
//   uint8_t ipHeaderLen = (ipHeader[0] & 0x0F) * 4; // IHL字段

//   // TCP头解析（ipHeader + ipHeaderLen）
//   uint8_t* tcpHeader = ipHeader + ipHeaderLen;
//   uint16_t srcPort = (tcpHeader[0] << 8) | tcpHeader[1];
//   uint16_t dstPort = (tcpHeader[2] << 8) | tcpHeader[3];

//   // 检测22端口流量
//   if (srcPort == 22 || dstPort == 22) {
//     Serial.println(">>> 检测到SSH流量 <<<");
//   }
// }
// 辅助函数：打印MAC地址
void printMac(uint8_t* mac) {
  for (int i = 0; i < 6; i++) {
    if (mac[i] < 0x10) Serial.print("0");
    Serial.print(mac[i], HEX);
    if (i < 5) Serial.print(":");
  }
  Serial.println();
}

// 辅助函数：打印IP地址
void printIp(uint8_t* ip) {
  for (int i = 0; i < 4; i++) {
    Serial.print(ip[i]);
    if (i < 3) Serial.print(".");
  }
  Serial.println();
}
bool isLinkUp() {
  return (readW5500Reg(0x002E, BSB_COMMON) & 0x01); // 检查PHYCFGR的LNK位
}

void clearRxBuffer() {
  writeW5500Reg(W5500_S0_RX_RD0, BSB_S0_REG, 0x00);
  writeW5500Reg(W5500_S0_RX_RD1, BSB_S0_REG, 0x00);
  writeW5500Reg(W5500_S0_CR, BSB_S0_REG, 0x40); // RECV命令
}
void setup() {
  Serial.begin(115200);
  delay(2000);
  
  Serial.println("\n===== W5500网络监听器 - 修正版 =====");
  
  pinMode(LED_PIN, OUTPUT);
  pinMode(CS_GPIO, OUTPUT);
  digitalWrite(CS_GPIO, HIGH);
  
  if (!initW5500()) {
    Serial.println("初始化失败 - 检查硬件连接");
    while (1) {
      digitalWrite(LED_PIN, !digitalRead(LED_PIN));
      delay(200);
    }
  }
  
  Serial.println("监听器已启动 - 等待数据包");
}

void loop() {
  static bool lastLinkState = false;
  bool currentLinkState = isLinkUp();
  
  if (currentLinkState != lastLinkState) {
    Serial.print("Link State Changed: ");
    Serial.println(currentLinkState ? "CONNECTED" : "DISCONNECTED");
    lastLinkState = currentLinkState;
    if (!currentLinkState) clearRxBuffer();
  }
  processPackets();
  delay(1);
}